﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CastleDefender.Object;
using CastleDefender.Object.Items;
using CastleDefender.Object.Monsters;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using CastleDefender.Platform.ScreenBehavior;
using CastleDefender.ConfigFolder;
using Microsoft.Xna.Framework.Media;

namespace CastleDefender.Platform.GameScene
{
    public partial class GameWorld : GameScene
    {
        #region VARIABLE

        protected Bow bow;
        protected Animation2D caslte;
        protected Items items;
        protected Monsters monsters;
        protected Arrows arrowsNormal;
        protected Arrows arrowsFire;
        protected Arrows arrowsElectric;
        protected Arrows arrowsCurrent;
        protected GameBar gameBar;
        protected Random radRandom;
        protected SpriteFont sfFont;
        protected TimeSpan tsTimeEffect;
        protected TimeSpan tsTimeEndGame;
        protected int intRandom;
        protected int intTypeEffect;
        protected bool blnEffect;
        protected bool blnStartEndEffect;
        protected bool blnWin;
        protected bool blnLose;
        protected bool blnEndGame;

        #endregion

        #region CONSTRUCTOR

        public GameWorld(Game myGame, ref TouchBehavior touch,
            int amountArrowNormal, int amountArrowFire, int amountArrowElectric,
            int Heart, int Score, int Level)
            : base(myGame, Config.FolderBackgrounds + "Play")
        {
            //Load hình ảnh
            sfFont = myGame.Content.Load<SpriteFont>(Config.FolderFonts + "FontWaiting");
            radRandom = new Random();
            blnWin = false;
            blnLose = false;
            blnEndGame = false;
           

            #region Texture cung

            //Cung
            Texture2D textureBow = myGame.Content.Load<Texture2D>(Config.FolderObject + "Bow");

            //Thành
            Texture2D textureCastle = myGame.Content.Load<Texture2D>(Config.FolderObject + "Castle");
            #endregion

            #region Texture mũi tên

            List<Texture2D> lstArrows = new List<Texture2D>();

            //Texture mũi tên bình thường
            Texture2D textureArrowNormal = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderArrows + "Normal");
            lstArrows.Add(textureArrowNormal);

            //Texture mũi tên lửa
            Texture2D textureArrowFire = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderArrows + "Fire");
            lstArrows.Add(textureArrowFire);

            //Texture mũi tên điện
            Texture2D textureArrowElectric = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderArrows + "Electric");
            lstArrows.Add(textureArrowElectric);

            #endregion

            #region Texture vật phẩm hỗ trợ
            List<Texture2D> lstSupItems = new List<Texture2D>();

            //Tăng số lượng tên thường
            Texture2D textureItemPlusArrowNormal = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "PLusArrowNormal");
            lstSupItems.Add(textureItemPlusArrowNormal);

            //Tăng số lượng tên lửa 
            Texture2D textureItemPlusArrowFire = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "PlusArrowFire");
            lstSupItems.Add(textureItemPlusArrowFire);

            //Tăng số lượng tên điện
            Texture2D textureItemPlusArrowElectric = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "PlusArrowElectric");
            lstSupItems.Add(textureItemPlusArrowElectric);

            //Tăng máu
            Texture2D textureItemPlusHeart = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "PlusHeart");
            lstSupItems.Add(textureItemPlusHeart);

            //Giảm tốc độ quái toàn map
            Texture2D textureIcheesLimitSpeedMonsters = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "LimitSpeedMonsters");
            lstSupItems.Add(textureIcheesLimitSpeedMonsters);

            #endregion

            #region Texture vật phẩm cản trở
            List<Texture2D> lstStupidItems = new List<Texture2D>();

            //Texture giảm số mũi tên lửa
            Texture2D textureMinusArrowFire = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "MinusArrowFire");
            lstStupidItems.Add(textureMinusArrowFire);

            //Texture giảm số mũi tên điện
            Texture2D textureMinusArrowElectric = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "MinusArrowElectric");
            lstStupidItems.Add(textureMinusArrowElectric);

            //Tăng tốc độ quái toàn map
            Texture2D texturePlusSpeedMonsters = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderItems + "PlusSpeedMonsters");
            lstStupidItems.Add(texturePlusSpeedMonsters);

            #endregion

            #region Texture quái vật đi bộ
            List<Texture2D> lstMonsterStupids = new List<Texture2D>();

            //Texture quái đi bộ hình dạng 1
            Texture2D textureMonsterStupid1 = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderMonsters + "MonsterStupid1");
            lstMonsterStupids.Add(textureMonsterStupid1);

            //Texture quái đi bộ hình dạng 2
            Texture2D textureMonsterStupid2 = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderMonsters + "MonsterStupid2");
            lstMonsterStupids.Add(textureMonsterStupid2);

            #endregion

            #region Texture quái bay
            List<Texture2D> lstMonsterFly = new List<Texture2D>();

            //Texture quái bay hình dạng 1
            Texture2D textureMonsterFly1 = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderMonsters + "MonsterFly1");
            lstMonsterFly.Add(textureMonsterFly1);

            //Texture quái bay hình dạng 2
            Texture2D textureMonsterFly2 = myGame.Content.Load<Texture2D>(Config.FolderObject + Config.FolderMonsters + "MonsterFly2");
            lstMonsterFly.Add(textureMonsterFly2);

            #endregion

            #region Texture Game Bar

            List<Texture2D> lstGameBar = new List<Texture2D>();
            lstGameBar.AddRange(lstArrows);

            #endregion

            int amountMonsterStupid = 0;
            int amountMonsterFly = 0;
            int timeCreateNewMonsterStupid = 0;
            int timeCreateNewMonsterFly = 0;
            InitMonstersOnTheLevel(Level, ref amountMonsterStupid, ref timeCreateNewMonsterStupid, ref amountMonsterFly, ref timeCreateNewMonsterFly);

            caslte = new Animation2D(myGame, ref textureCastle, 135, 135, true, false, new Vector2((Config.ScreenSize.X - 135) / 2, Config.GameSurFace - 135), 1000);
            bow = new Bow(myGame, ref textureBow, 45, 45, ref touch, Config.BowInitPosition, new Vector2(0, 1), Heart);
            arrowsNormal = new Arrows(myGame, ref textureArrowNormal, 45, 45, bow.Position, 0, amountArrowNormal, bow.Rotation, Config.GameBounds);
            arrowsFire = new Arrows(myGame, ref textureArrowFire, 45, 45, bow.Position, 1, amountArrowFire, bow.Rotation, Config.GameBounds);
            arrowsElectric = new Arrows(myGame, ref textureArrowElectric, 45, 45, bow.Position, 2, amountArrowElectric, bow.Rotation, Config.GameBounds);
            monsters = new Monsters(myGame, ref lstMonsterStupids, ref lstMonsterFly, 45, 45, amountMonsterStupid, amountMonsterFly, timeCreateNewMonsterStupid, timeCreateNewMonsterFly, bow.Position);
            items = new Items(myGame, ref lstSupItems, ref lstStupidItems, 45, 45, Config.GameBounds);
            gameBar = new GameBar(myGame, ref lstGameBar, new Vector2(0, 0), ref touch);
            gameBar.GetInfo(arrowsNormal.Amount, arrowsFire.Amount, arrowsElectric.Amount, bow.Heart);
            bow.CaslteBounds = new Rectangle((int)caslte.Bounds.X, (int)caslte.Bounds.Y + 40, caslte.Bounds.Width, caslte.Bounds.Height - 40);
            gameBar.Score = Score;
            gameBar.Level = Level;

            lstComponents.Add(caslte);
            lstComponents.Add(bow);
            lstComponents.Add(arrowsNormal);
            lstComponents.Add(arrowsFire);
            lstComponents.Add(arrowsElectric);
            lstComponents.Add(monsters);
            lstComponents.Add(items);
            lstComponents.Add(gameBar);


        }

        #endregion

        #region PUBLIC METHOD

        public override void Show()
        {
            blnPause = false;
            gameBar.Pause = false;
            blnWin = false;
            blnLose = false;
            blnEndGame = false;
            MediaPlayer.Play(audio.Play);
            MediaPlayer.IsRepeating = true;
            base.Show();
        }

        public override void Hide()
        {
            base.Hide();
        }

        public override void Update(GameTime gameTime)
        {
            if (Enabled && Visible)
            {
                //Cập nhật các quy tắc thắng thua
                UpdateWinLose();

                if (!blnWin && !blnLose)
                {
                    if (gameBar.Pause)
                    {
                        blnPause = gameBar.Pause;
                    }

                    if (!blnPause)
                    {
                        //Cập các trạng thái mũi tên nhận được từ cung
                        UpdateStateArrows();

                        //Xét mũi tên đang sử dụng
                        SetCurrentArrows();

                        //Va chạm giữa các mũi tên và quái vật
                        UpdateArrows(ref arrowsNormal);
                        UpdateArrows(ref arrowsFire);
                        UpdateArrows(ref arrowsElectric);

                        //Cập nhật hiệu ứng của quái vật nhận từ Item
                        UpdateEffectOfItem(gameTime);

                        //Cập nhật máu
                        UpdateMonsterAttackCaslte();
                    }
                    base.Update(gameTime);
                }
                
            }
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            //Tạm dừng trước khi kết thúc màn chơi
            if (blnLose || blnWin)
            {
                tsTimeEndGame += gameTime.ElapsedGameTime;
                if (tsTimeEndGame > TimeSpan.FromSeconds(Config.TimeWaiting - 1))
                {
                    tsTimeEndGame = TimeSpan.Zero;
                    blnEndGame = true;
                }
            }

            if (blnLose)
            {
                string lose = "LOSE";
                Vector2 measure = sfFont.MeasureString(lose);
                Vector2 pos = (Config.ScreenSize - measure) / 2 - new Vector2(0, 45);
                sprBatch.DrawString(sfFont, lose, pos, Color.White);
            }

            if (blnWin)
            {
                string win = "WIN";
                string nextLvl = "NEXT LEVEL " + (gameBar.Level + 1).ToString();
                Vector2 measureWin = sfFont.MeasureString(win);
                Vector2 measureNextLevel = sfFont.MeasureString(nextLvl);
                Vector2 pos = (Config.ScreenSize - measureWin) / 2 - new Vector2(0, measureWin.Y + 45);
                Vector2 posnext = (Config.ScreenSize - measureNextLevel) / 2 - new Vector2(0, 45);
                sprBatch.DrawString(sfFont, win, pos, Color.White);
                sprBatch.DrawString(sfFont, nextLvl, posnext, Color.White);
            }

        }

        #endregion

        #region PRIVATE METHOD

        //Cập nhật các thay đổi, va chạm của mũi tên trong game world
        private void UpdateArrows(ref Arrows arrows)
        {
            for (int j = 0; j < arrows.ListArrows.Count; j++)
            {
                //Nếu đã được bắn và chưa trúng đích, xét với toàn bộ quái
                if (arrows.ListArrows[j].Shoot && !arrows.ListArrows[j].OnTarget)
                {
                    gameBar.GetInfo(arrowsNormal.Amount, arrowsFire.Amount, arrowsElectric.Amount,bow.Heart);

                    //Xét va chạm với quái
                    for (int i = 0; i < monsters.ListMonsters.Count; i++)
                    {
                        //Chỉ xét va chạm với quái còn sống
                        if (monsters.ListMonsters[i].State != Config.StateDead)
                        {
                            //Nếu mũi tên bình thường thì xét va chạm với quái theo năng lượng bình thường
                            if (arrows.Type == 0 && monsters.ListMonsters[i].Bounds.Intersects(arrows.ListArrows[j].ArrowHeadBounds) && !arrows.ListArrows[j].OnTarget)
                            {
                                monsters.ListMonsters[i].Attacked(arrows.ListArrows[j].Power);
                                arrows.ListArrows[j].OnTarget = true;
                            }

                            //Nếu mũi tên lửa thì tăng dame
                            else if (arrows.Type == 1 && monsters.ListMonsters[i].Bounds.Intersects(arrows.ListArrows[j].ArrowHeadBounds) && !arrows.ListArrows[j].OnTarget)
                            {
                                monsters.ListMonsters[i].Attacked((int)(arrows.ListArrows[j].Power * 1.5));
                                monsters.ListMonsters[i].MoveStep = Config.MonsterMoveStepNormal;
                                arrows.ListArrows[j].OnTarget = true;
                            }

                            //Nếu mũi tên điện thì lan rộng giảm dame
                            else if (arrows.Type == 2 && monsters.ListMonsters[i].Bounds.Intersects(arrows.ListArrows[j].Bounds))
                            {
                                monsters.ListMonsters[i].Attacked((int)(arrows.ListArrows[j].Power * 0.8));
                                arrows.ListArrows[j].OnTarget = true;

                            }

                            //Sau khi xử lý va chạm với mũi tên tính điểm khi giết được quái
                            //Quái đi bộ
                            if (monsters.ListMonsters[i].State == Config.StateDead)
                            {
                                if (monsters.ListMonsters[i] is MonsterStupid)
                                {
                                    gameBar.Score += Config.MonsterStupidScore;
                                }
                                else
                                {
                                    gameBar.Score += Config.MonsterFlyScore;
                                }
                            }
                         


                        }

                    }

                    //Xét va chạm với vật phẩm
                    for (int k = 0; k < items.ListItems.Count; k++)
                    {
                        if (items.ListItems[k].Bounds.Intersects(arrows.ListArrows[j].ArrowHeadBounds))
                        {
                            arrows.ListArrows[j].OnTarget = true;

                            //Truyền các thuộc tính nhận được khi kích hoạt vật phẩm
                            if (items.ListItems[k].Visible)
                            {
                                GetItem(items.ListItems[k]);
                                items.ListItems[k].SetPropety(intRandom);
                                gameBar.GetInfo(arrowsNormal.Amount, arrowsFire.Amount, arrowsElectric.Amount,bow.Heart);
                            }

                        }
                    }
                }
            }
        }

        //Cập nhật các trạng thái mũi tên
        private void UpdateStateArrows()
        {
            //Cập nhật trạng thái mũi tên thường
            if (arrowsNormal.Available)
            {
                arrowsNormal.Attack(bow.Power, bow.Rotation, bow.Attack, bow.Touch, bow.VectorDirection);
                bow.Shot(arrowsNormal.Shoot);
            }

            //Cập nhật trạng thái mũi tên lửa
            if (arrowsFire.Available)
            {
                arrowsFire.Attack(bow.Power, bow.Rotation, bow.Attack, bow.Touch, bow.VectorDirection);
                bow.Shot(arrowsFire.Shoot);
            }

            //Cập nhật trạng thái mũi tên băng
            if (arrowsElectric.Available)
            {
                arrowsElectric.Attack(bow.Power, bow.Rotation, bow.Attack, bow.Touch, bow.VectorDirection);
                bow.Shot(arrowsElectric.Shoot);
            }

        }

        //Cập nhật các mũi tên hiện tại
        private void SetCurrentArrows()
        {
            if (gameBar.TypeArrows == 0)
            {
                arrowsCurrent = arrowsNormal;
                arrowsNormal.Available = true;
                arrowsFire.Available = false;
                arrowsElectric.Available = false;
            }
            else if (gameBar.TypeArrows == 1)
            {
                arrowsCurrent = arrowsFire;
                arrowsNormal.Available = false;
                arrowsFire.Available = true;
                arrowsElectric.Available = false;
            }
            else if (gameBar.TypeArrows == 2)
            {
                arrowsCurrent = arrowsElectric;
                arrowsNormal.Available = false;
                arrowsFire.Available = false;
                arrowsElectric.Available = true;
            }

        }

        //Phân loại và lấy thuộc tính vật phẩm
        private void GetItem(Item item)
        {
            //Vật phẩm hỗ trợ
            if (item.SupItem)
            {
                switch (item.Type)
                {
                    //Tăng số lượng tên thường
                    case 0:
                        {
                            intRandom = radRandom.Next(100) % Config.ItemMaxAmount + 5;
                            arrowsNormal.Amount += intRandom;
                            break;
                        }
                    //Tăng số lượng tên lửa
                    case 1:
                        {
                            intRandom = radRandom.Next(100) % Config.ItemMaxAmount + 5;
                            arrowsFire.Amount += intRandom;
                            break;
                        }
                    //Tăng số lượng tên băng
                    case 2:
                        {
                            intRandom = radRandom.Next(100) % Config.ItemMaxAmount + 5;
                            arrowsElectric.Amount += intRandom;
                            break;
                        }
                    //Tăng máu
                    case 3:
                        {
                            intRandom = radRandom.Next(1000) % Config.ItemMaxHeart + 100;
                            bow.Heart += intRandom;
                            if (bow.Heart > Config.BowHeartCastle)
                            {
                                bow.Heart = Config.BowHeartCastle;
                            }
                            break;
                        }

                    //Giảm tốc độ quái có trên map
                    case 4:
                        {
                            intRandom = 0;
                            intTypeEffect = 1;
                            blnEffect = true;
                            blnStartEndEffect = true;
                            tsTimeEffect = TimeSpan.Zero;
                            gameBar.GetMoveStepItem(Config.MonsterMoveStepVerySlow);
                            break;
                        }
                }
            }

            //Vật phẩm gây bất lợi
            else
            {
                switch (item.Type)
                {
                    //Trừ số lượng tên lửa
                    case 0:
                        {
                            intRandom = -(radRandom.Next(100) % Config.ItemMaxAmount + 5);
                            arrowsFire.Amount += intRandom;
                            break;
                        }
                    //Trừ số lượng tên băng
                    case 1:
                        {
                            intRandom = -(radRandom.Next(100) % Config.ItemMaxAmount + 5);
                            arrowsElectric.Amount += intRandom;
                            break;
                        }
                    // Tăng tốc độ quái trên map
                    case 2:
                        {
                            intRandom = 0;
                            intTypeEffect = 2;
                            blnEffect = true;
                            blnStartEndEffect = true;
                            tsTimeEffect = TimeSpan.Zero;
                            gameBar.GetMoveStepItem(Config.MonsterMoveStepFast);
                            break;
                        }
                }
            }
        }

        //Hiệu ứng của vật phẩm và tên đối với quái
        private void UpdateEffectOfItem(GameTime gameTime)
        {
            //Thời gian tồn tại của hiệu ứng
            if (blnEffect)
            {
                tsTimeEffect += gameTime.ElapsedGameTime;
                if (tsTimeEffect >= TimeSpan.FromSeconds(Config.ItemTimeEffect))
                {
                    tsTimeEffect = TimeSpan.Zero;
                    blnEffect = false;
                    intTypeEffect = 0;
                    gameBar.GetMoveStepItem(Config.MonsterMoveStepNormal);
                    blnStartEndEffect = true;
                }

            }

            //Khi thể hiện hiệu ứng của được bắt đầu hoặc kết thúc sẽ xét hiệu ứng cho quái
            if (blnStartEndEffect)
            {
                for (int i = 0; i < monsters.ListMonsters.Count; ++i)
                {
                    //Kết thúc hiệu ứng
                    if (intTypeEffect == 0)
                    {
                        monsters.ListMonsters[i].MoveStep = Config.MonsterMoveStepNormal;
                        monsters.ListMonsters[i].TimeChangeFrames = Config.MonsterTimeChangeFrame;
                    }

                    //Hiệu ứng giảm tốc
                    if (intTypeEffect == 1)
                    {
                        monsters.ListMonsters[i].MoveStep = Config.MonsterMoveStepVerySlow;
                        monsters.ListMonsters[i].TimeChangeFrames = Config.MonsterTimeChangeFrame + Config.MonsterSpeedEffect;
                    }

                    //Hiệu ứng tăng tốc
                    if (intTypeEffect == 2)
                    {
                        monsters.ListMonsters[i].MoveStep = Config.MonsterMoveStepFast;
                        monsters.ListMonsters[i].TimeChangeFrames = Config.MonsterTimeChangeFrame - Config.MonsterSpeedEffect;
                    }
                }

                blnStartEndEffect = false;
            }
        }

        //Cập nhật máu của thành khi 
        private void UpdateMonsterAttackCaslte()
        {
            for (int i = 0; i < monsters.ListMonsters.Count; i++)
            {
                if (monsters.ListMonsters[i].Bounds.Intersects(bow.CaslteBounds) && monsters.ListMonsters[i].Life != 0)
                {
                    //Tấn công của quái bay
                    if (monsters.ListMonsters[i] is MonsterFly)
                    {
                        bow.Heart -= Config.MonsterFlyDame;
                        monsters.ListMonsters[i].Life = 0;
                    }

                    //Tấn công của quái đi
                    else
                    {
                        int state = Config.StateStandby;
                        if (monsters.ListMonsters[i].ActiveFrame == monsters.ListMonsters[i].Frames[state].Count - 1
                            && monsters.ListMonsters[i].State == state)
                        {
                            bow.Heart -= Config.MonsterStupidDame;
                        }
                    }

                    if (bow.Heart < 0)
                    {
                        bow.Heart = 0;
                    }

                    gameBar.GetInfo(arrowsNormal.Amount, arrowsFire.Amount, arrowsElectric.Amount, bow.Heart);
                }
            }
        }

        //Cập nhật bắt đầu, kết thúc màn chơi
        private void UpdateWinLose()
        {
            //Thua nếu hết tên hoặc hết máu 
            if ((arrowsNormal.Amount == 0
                && arrowsNormal.ListArrows.Count == 0
                && arrowsFire.Amount == 0
                && arrowsFire.ListArrows.Count == 0
                && arrowsElectric.Amount == 0
                && arrowsElectric.ListArrows.Count == 0)
                || bow.Heart == 0)
            {
                blnLose = true;
            }

            //Khi giết hết quái trong màn
            else if (monsters.ListMonsters.Count == 0 && monsters.Amount == 0)
            {
                blnWin = true;
            }
        }

        //Khởi tạo độ khó theo cấp độ
        private void InitMonstersOnTheLevel(int level,ref int amountStupid, ref int timeStupid, ref int amountFly, ref int timeFly)
        {
            amountStupid = Config.InitMonsterStupid * level;
            timeStupid = Config.InitTimeCreateMonsterStupid - level / 2;
            amountFly = (int)((Config.InitMonsterFly + 1) * (level - 1) * 2.5f);
            timeFly = Config.InitTimeCreateMonsterFly - level / 2 * 4;

            if (timeStupid < 2) timeStupid = 2;
            if (timeFly < 7) timeFly = 3;
        }

        #endregion

        #region PUBLIC PROPERTIES

        //Nhận trả giá trị blnPause
        public bool Pause
        {
            get { return blnPause; }
            private set { }
        }

        //Trả giá trị blnWin
        public bool Win
        {
            get { return blnWin; }
            private set { }
        }

        //Trả giá trị blnLose
        public bool Lose
        {
            get { return blnLose; }
            private set { }
        }

        //Trả giá trị blnEndGame
        public bool End
        {
            get { return blnEndGame; }
            private set { }
        }

        //Trả giá trị số lượng tên thường
        public int AmountArrowNormal
        {
            get { return arrowsNormal.Amount; }
            private set { }
        }

        //Trả giá trị số lượng tên lửa
        public int AmountArrowFire
        {
            get { return arrowsFire.Amount; }
            private set { }
        }

        //Trả giá trị số lượng tên băng
        public int AmountArrowElectric
        {
            get { return arrowsElectric.Amount; }
            private set { }
        }

        //Trả giá trị mạng 
        public int Heart
        {
            get { return bow.Heart; }
            private set { }
        }

        //Trả giá tri score
        public int Score
        {
            get { return gameBar.Score; }
        }

        //Trả giá trị Level
        public int Level
        {
            get { return gameBar.Level; }
        }
        #endregion

    }
}
